﻿using System;
using System.Collections.Generic;
using System.IO;

namespace SNWordLParser{
    class WordParser{
        ReservedTable[] reservedWords = { 
	    new ReservedTable("program",LexType.PROGRAM),
	    new ReservedTable("type",LexType.TYPE),
	    new ReservedTable("var",LexType.VAR),
	    new ReservedTable("procedure",LexType.PROCEDURE),
	    new ReservedTable("begin",LexType.BEGIN),
	    new ReservedTable("end",LexType.END),
	    new ReservedTable("array",LexType.ARRAY),
	    new ReservedTable("of",LexType.OF),
	    new ReservedTable("record",LexType.RECORD),
	    new ReservedTable("if",LexType.IF),
	    new ReservedTable("then",LexType.THEN),
	    new ReservedTable("else",LexType.ELSE),
	    new ReservedTable("fi",LexType.FI),
	    new ReservedTable("while",LexType.WHILE),
	    new ReservedTable("do",LexType.DO),
	    new ReservedTable("endwh",LexType.ENDWH),
	    new ReservedTable("read",LexType.READ),
	    new ReservedTable("write",LexType.WRITE),
	    new ReservedTable("return",LexType.RETURN),
	    new ReservedTable("integer",LexType.INTEGER),
	    new ReservedTable("char",LexType.CHAR1)
	    };
        private StreamReader source = null; 
        private string tokenString = null;
        private string lineBuf = null;//一行字符串
        private int length;//buffer的长度
        private int linepos = 0;//字符串的指针，标识处理位置
        private bool  EOF_flag ;//表示文件结束
        private Global global;

        private List<TokenType> list=new List<TokenType>();//存储token序列的链表
        public  List<TokenType> getList(){return list;}
        public WordParser(Global g)
        {
            this.global = g;
            linepos = 0; 
            EOF_flag = false ;
            global.operateError=false;
            global.operateTokentnum = 0;
            global.operatelineno = 0;
            length = 0;
          //  sin = new StreamReader(path);
        }
        public void  getTokenList(String path){ 
	        global.operatelineno = 0;
            linepos = 0;
            length = 0;
	        global.operateTokentnum=0;
            EOF_flag = false;
            global.operateError = false;
            source = new StreamReader(path);
            if (source == null)
            {
                window.WriteLine("未找到源文件");
                global.operateError = true;
                return;
            }
   
           TokenType currentToken=new TokenType();   
        do { 
           StateType state = StateType.START;
           bool save;
           tokenString = "";
           while (state !=StateType.DONE)
           {
	         int c = getNextChar();
             save = true;					
             switch (state)
             { 
                   case StateType.START:
		                 if (isdigit(c))
                              state = StateType.INNUM;				

                           else if (isalpha(c))
                                state = StateType.INID;				
                           else if (c == ':')
                              state = StateType.INASSIGN;		
                           
		                 else if (c == '.')
                             state = StateType.INRANGE;

		                 else if (c == '\'')
		                     { save = false;
                             state = StateType.INCHAR;
                             }	   
		                 
                         else if ((c == ' ') || (c == '\t')){
                           save =false;
                          // Window.WriteLine("1111111111111111111111");
                         }
                         else if ((c == '\n')) { save = false;// Window.WriteLine("2222222222222");
                         }
                         else if (c == '{')
                         { save = false;
                           state = StateType.INCOMMENT;			
                         }
                         else
                         {
                           state = StateType.DONE;
                           switch (c)
                           {
                               case -1://-1表示文件结束
                               save = false;
                               currentToken.Lex =LexType.ENDFILE1;//表示文件结束
                               break;					

			                 /* 当前字符c为"=",当前识别单词返回值currentToken设置为等号单词EQ */
                             case '=':
                               currentToken.Lex = LexType.EQ;
                               break;

			                 /* 当前字符c为"<",当前识别单词返回值currentToken设置为小于单词LT */
                             case '<':
                               currentToken.Lex = LexType.LT;
                               break;

			                 /* 当前字符c为"+",当前识别单词返回值currentToken设置为加号单词PLUS */
                             case '+':
                               currentToken.Lex = LexType.PLUS;
                               break;

			                 /* 当前字符c为"-",当前识别单词返回值currentToken设置为减号单词MINUS */
                             case '-':
                               currentToken.Lex = LexType.MINUS;
                               break;

			                 /* 当前字符c为"*",当前识别单词返回值currentToken设置为乘号单词TIMES */
                             case '*':
                               currentToken.Lex = LexType.TIMES;
                               break;

			                 /* 当前字符c为"/",当前识别单词返回值currentToken设置为除号单词OVER */
                             case '/':
                               currentToken.Lex = LexType.OVER;
                               break;
                             case '[':
                               currentToken.Lex = LexType.LMIDPAREN;
                               break;
                             case ']':
                               currentToken.Lex = LexType.RMIDPAREN;
                               break;
                             case '(':
                               currentToken.Lex = LexType.LPAREN;
                               break;

                             case ')':
                               currentToken.Lex = LexType.RPAREN;
                               break;

                             case ';':
                               currentToken.Lex = LexType.SEMI;
                               break;
 			                 case ',':
                               currentToken.Lex = LexType.COMMA;
                               break;     		 			         
                             default:
                               currentToken.Lex = LexType.ERROR1;
                               global.operateError = true;
			                   break;
                           }
                         }//里层的switch
                     break;					
               case StateType.INCOMMENT:
                 save =false;				
                 if (c == -1)
                 {
                   state = StateType.DONE;
                   currentToken.Lex = LexType.ENDFILE1;

                 }  
                 else if (c == '}') state = StateType.START;
                 break;
               case StateType.INASSIGN:				
                 state = StateType.DONE;				
		         if (c == '=')
                     currentToken.Lex = LexType.ASSIGN;
                 else
                 { 
                   ungetNextChar();
                   save = false;
                   currentToken.Lex = LexType.COLON;
                 }
                 break;
        
	           case StateType.INRANGE:				
                 state = StateType.DONE;				
		         if (c == '.')
                   currentToken.Lex = LexType.UNDERANGE;
                 else
                 { 
                   ungetNextChar();
                   save = false;
                   currentToken.Lex = LexType.DOT;
                 }
                 break;
 
               case StateType.INNUM:					

                 if (!isdigit(c))
                 { 
                   ungetNextChar();
                   save = false;
                   state = StateType.DONE;
                   currentToken.Lex = LexType.INTC;
                 }
                 break;
               case StateType.INCHAR:					

                 if (isalnum(c))
        
		         { int c1=getNextChar();
                    if (c1 =='\'')
			        { save = true;
                      state = StateType.DONE;
			          currentToken.Lex = LexType.CHARC;
			        }
		            else 
			        {	ungetNextChar();
                        ungetNextChar();
			            //save = TRUE;
                        state = StateType.DONE;
                        currentToken.Lex =LexType.ERROR1;
				        global.operateError = true;
			        }
		         }
		         else
		         {      ungetNextChar();
			            //save = TRUE;
                        state = StateType.DONE;
                        currentToken.Lex = LexType.ERROR1;
                        global.operateError = true;
			      }
		         break;
               case StateType.INID:					
                 if (!isalnum(c))
                 { 
                   ungetNextChar();
                   save = false;
                   state = StateType.DONE;
                   currentToken.Lex = LexType.ID;
                 }
                 break;
               case StateType.DONE:	break;	

               default: 
                 window.WriteLine("Scanner Bug: state= " + state + "\n");
                 state = StateType.DONE;
                 currentToken.Lex = LexType.ERROR1;
		         global.operateError = true;
                 break;
             }//第一层switch
             if (save)
               tokenString+=(char) c;
	         if (state == StateType.DONE)
               {	       
                     if (currentToken.Lex == LexType.ID){
                             currentToken.Lex = reservedLookup(tokenString);
                      }
               }
           }//while
           currentToken.lineshow = global.operatelineno;
           currentToken.Sem = tokenString;
           list.Add(currentToken);
           global.operateTokentnum=global.operateTokentnum+1;
           //Window.WriteLine("tokenString :"+tokenString);
           tokenString = "";
         }while ((currentToken.Lex)!=LexType.ENDFILE1);
        window.WriteLine("end of get token list");
        source.Close();

        }
        public void printTokenlist() {
            window.WriteLine("输出TokenList（即是list）中信息");
            int num;
            TokenType currentToken;
            if (global.operateError)
                window.WriteLine("----词法分析有错，以ERROR打头的为错误的Token：\n");
            else window.WriteLine("----词法分析无错：Token序列如下：\n");
            int count=list.Count;
            if (count<=0)
            {
                window.WriteLine( "Token序列为空");
                return;
            }
            for (num = 0; num < global.operateTokentnum; num++)
            {
                currentToken = list[num];
                window.Write("行号: "+currentToken.lineshow);
                printToken(currentToken);
            }
        }
        protected int getNextChar(){ 
            if (!(linepos < length)){
                global.operatelineno = global.operatelineno + 1;
                if (global.operateTokentnum > 0)
                {
                    TokenType tokenline = new TokenType();
                    tokenline.lineshow = 0;
                    tokenline.Lex = LexType.CRT;//存储一个换行符号
                    tokenline.Sem = "\n";
                    list.Add(tokenline);
                    global.operateTokentnum = global.operateTokentnum + 1;
                }
               
	            if ((lineBuf = source.ReadLine()) != null)	
	            {
                    lineBuf = "   " + lineBuf;
                   // Window.WriteLine("buffer "+lineBuf);
                    length = lineBuf.Length;
                    //Window.WriteLine("buffer length :"+length);
	                linepos = 0;       
                     return lineBuf[linepos++];
                } else{ 
	                EOF_flag = true;					
	                return -1;
               }
            }
             else return lineBuf[linepos++];
        }

        protected void ungetNextChar(){//将字符重新放回缓冲区中
            if (!EOF_flag)
                linepos--;
        }
       protected void printToken(TokenType token) { 
            switch (token.Lex){
                                case LexType.PROGRAM:
                                case LexType.PROCEDURE:
                                case LexType.TYPE:
                                case LexType.VAR:
                                case LexType.IF:
                                case LexType.THEN:
                                case LexType.ELSE:
                                case LexType.FI:
                                case LexType.WHILE:
                                case LexType.DO:
                                case LexType.ENDWH:
                                case LexType.BEGIN:
                                case LexType.END:
                                case LexType.READ:
                                case LexType.WRITE:
                                case LexType.ARRAY:
                                case LexType.OF:
                                case LexType.RECORD:
                                case LexType.RETURN:    
                                case LexType.INTEGER:
                                case LexType.CHAR1:       
                            window.WriteLine("reserved word: "+token.Sem);
                            break;
                                case LexType.ASSIGN: window.WriteLine(":="); break;
    
                                case LexType.LT: window.WriteLine("<"); break;
  
                                case LexType.EQ: window.WriteLine("="); break;
    
                                case LexType.PLUS: window.WriteLine("+"); break;
 
                                case LexType.MINUS: window.WriteLine("-");  break;

                                case LexType.TIMES: window.WriteLine("*"); break;

                                case LexType.OVER: window.WriteLine("/"); break;

                                case LexType.LPAREN: window.WriteLine("("); break;

                                case LexType.RPAREN: window.WriteLine(")"); break;

                                case LexType.LMIDPAREN: window.WriteLine("["); break;    
	
                                case LexType.RMIDPAREN: window.WriteLine("]"); break; 

                                case LexType.SEMI: window.WriteLine(";"); break;
	        
                                case LexType.COLON: window.WriteLine(":"); break;	
	       
                                case LexType.COMMA: window.WriteLine(","); break;	
		       
                                case LexType.DOT: window.WriteLine("."); break;	
	       
                                case LexType.UNDERANGE: window.WriteLine(".."); break;
     
                                case LexType.ENDFILE1: window.WriteLine("EOF"); break;
    
                                case LexType.INTC:
                                    window.WriteLine( "INTC, val= "+token.Sem);
                                break;

                                case LexType.CHARC:
                                  window.WriteLine("CHARC, letter= "+token.Sem);
                                  break;
	  
                                case LexType.ID:
                                  window.WriteLine( "ID, name= "+token.Sem);
                                  break;

                                case LexType.ERROR1:
                                  window.WriteLine("ERROR: "+token.Sem);
                                  break;
                              case LexType.CRT:
                                  window.WriteLine("记录的是换行符号");
                                  break;
                                default: 
                                  window.WriteLine("Unknown token:"+token.Lex);
                                  break;
                              }
        }
    
        protected LexType reservedLookup(String str) {
            int i;
            for (i = 0; i < reservedWords.Length; i++)
                if (reservedWords[i].str.Equals(str))
                    return (reservedWords[i].tok);
            return LexType.ID;
        }
        protected bool isdigit(int i) {
            if (i >= 48 && i <= 57) return true;
            else return false;
        }
        protected bool isalpha(int c){
            if ((c >= 65 && c <= 90)||(c>=97&&c<=122)) return true;
            else return false;
        }
        protected bool isalnum(int c){
            bool flag;
            flag=isdigit(c);
            if (flag == false)
                flag = isalpha(c);
            return flag;
        }
    }
}
